#include "Task.hpp"
#include <iostream>
#include <cstdio>
#include<vector>
#include <sys/wait.h>
#define SIZE 3
//./processpool 3
// 封装管道
class Channel
{
public:
    Channel(int wfd, pid_t subprocessid, std::string name)
        : _wfd(wfd), _subprocessid(subprocessid), _name(name)
    {
    }
    int GetWfd()
    {
        return _wfd;
    }
    pid_t GetSubProcessId()
    {
        return _subprocessid;
    }
    std::string GetName()
    {
        return _name;
    }
    void Closewfd()
    {
        close(_wfd);
        std::cout<<"pid:"<<_subprocessid<<" has closed"<<std::endl;
    }
    void Wait()
    {
        pid_t rid = waitpid(_subprocessid,nullptr,0);
        if(rid > 0)
        {
            std::cout<<"pid:"<<_subprocessid<<" has quited"<<std::endl;
       }
    }
    ~Channel()
    {
    }

private:
    int _wfd;            // 父进程的读端
    pid_t _subprocessid; // 子进程的pid
    std::string _name;
};
void CreatPipeAndProcess(int num,std::vector<Channel>& channels,task_t task)
{
    for(int i = 0;i < num;i++)
    {
        //1.创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        if(n < 0) exit(-1);
        //2.创建子进程
        pid_t id = fork();
        //子进程
        if(id == 0)
        {
            close(pipefd[1]);
            //第二次创建管道后，关闭继承的父进程的w端，确保管道与子进程意义对应
            if(!channels.empty())
            {
                for(auto& e : channels)
                {
                    e.Closewfd();
                }
            }
            //将管道的r端重定向到标准输入里，实现解耦
            dup2(pipefd[0],0);
            //每一个进程完成自己的任务后退出
            task();
            close(pipefd[0]);
            exit(0);
        }
        std::cout << "pid:"<<id<<" has created"<<std::endl;
        //父进程
        close(pipefd[0]);
        //3.构建Channel名称
        std::string comman = "Channel-";
        comman = comman + std::to_string(i);
        channels.push_back(Channel(pipefd[1],id,comman));
    }
}
int NextChannel(int process_num)
{
    static int index = -1;
    index++;
    index %= process_num;
    return index;
}
void SendTaskToChannel(Channel channel,int command,int index)
{
    write(channel.GetWfd(),&command,sizeof(command));
    std::cout << "Sending task " << command << " to channel " << index << std::endl;
}

void ControlProcessOnce(std::vector<Channel>& channels,int process_num)
{
    //1.选择任务
    int command = SelectTask();
    //2.选择信道
    int index = NextChannel(process_num);
    //3.给指定信道派发任务
    SendTaskToChannel(channels[index],command,index);
}
//task_num执行任务次数
void ControlProcess(std::vector<Channel>& channels,int task_num = -1,int process_num = 0)
{
    if(task_num == -1)
    {
        while(true)
        {
            ControlProcessOnce(channels,process_num);
        }
    }
    else
    {
    
        while(task_num--)
        {
            ControlProcessOnce(channels,process_num);
        }
    }
}
void Clean(std::vector<Channel>& channels)
{
    for(auto& e : channels)
    {
        e.Closewfd();
        e.Wait();
    }
}
int main(int argc, char *argv[])
{
    // 1.确保命令行参数个数足够，创建足够的子进程
    // bash维护的命令行参数表
    if (argc != 2)
    {
        std::cerr << "Usage:" << argv[0] << "processnum" << std::endl;
    }
    // 2.获取子进程数目
    int num = std::stoi(argv[1]);
    // 3.提前为父进程加载任务
    LoadTask();
    // 4.生成匿名管道和一一对应的子进程
    // 4.1创建一个维护管道的数组
    std::vector<Channel> channels;
    // 4.2循环创建
    CreatPipeAndProcess(num,channels,work);//回调函数
    //5.通过channels控制子进程,此时父进程往不同的管道轮询写入任务码
    ControlProcess(channels,3,num);
    //6.回收子进程
    Clean(channels);
    return 0;
}